package com.fight.strive.sys.modules.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fight.strive.sys.modules.rbac.constants.RbacRoleConstants;
import com.fight.strive.sys.modules.rbac.dao.RbacOrgRoleMapper;
import com.fight.strive.sys.modules.rbac.dto.RbacOrgRoleDto;
import com.fight.strive.sys.modules.rbac.entity.RbacOrgRoleEntity;
import com.fight.strive.sys.modules.rbac.entity.RbacRoleEntity;
import com.fight.strive.sys.modules.rbac.service.RbacOrgRoleService;
import com.fight.strive.sys.modules.rbac.service.RbacRoleService;
import com.fight.strive.sys.utils.CollectionUtils;
import com.fight.strive.sys.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * @author ZHOUXIANG
 */
@Service
@Slf4j
public class RbacOrgRoleServiceImpl
        extends ServiceImpl<RbacOrgRoleMapper, RbacOrgRoleEntity>
        implements RbacOrgRoleService {

    @Resource
    private RbacRoleService rbacRoleService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(@Valid RbacOrgRoleDto dto) {
        // 清除组织角色
        this.delete(dto);
        // 设置组织角色
        if (CollectionUtils.isNotEmpty(dto.getRoleIds())) {
            List<RbacOrgRoleEntity> list = new ArrayList<>();
            dto.getRoleIds().forEach(id -> {
                RbacRoleEntity roleEntity = rbacRoleService.getById(id);
                RbacOrgRoleEntity orgRoleEntity = new RbacOrgRoleEntity();
                orgRoleEntity.setOrgId(dto.getOrgId())
                        .setRoleId(roleEntity.getId())
                        .setRoleCode(roleEntity.getRoleCode())
                        .setRoleName(roleEntity.getRoleName());
                this.saveOrUpdate(orgRoleEntity);
                list.add(orgRoleEntity);
            });
            // 更新缓存
            this.updateRedisData(dto.getOrgId(), list);
        }
    }

    @Override
    public void delete(RbacOrgRoleDto dto) {
        QueryWrapper<RbacOrgRoleEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("org_id", dto.getOrgId());
        // 删除缓存
        this.deleteRedisData(dto.getOrgId());
        // 删除数据库
        this.remove(queryWrapper);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Long> getIds(Long orgId) {
        List<Long> ids = (List<Long>) redisTemplate.opsForHash().get(
                RbacRoleConstants.ORG_ROLE_IDS_KEY, orgId);
        if (ObjectUtils.isNull(ids)) {
            ids = new ArrayList<>();
            // 从缓存中读取，没有就从数据库读取，并更新所有缓存
            List<RbacOrgRoleEntity> list = this.getOrgRoleListByOrgId(orgId);
            if (CollectionUtils.isNotEmpty(list)) {
                for (RbacOrgRoleEntity entity : list) {
                    ids.add(entity.getRoleId());
                }
            }
            // 空列表也缓存
            redisTemplate.opsForHash().put(
                    RbacRoleConstants.ORG_ROLE_IDS_KEY, orgId, ids);
        }
        return ids;
    }

    @Override
    @SuppressWarnings("unchecked")
    public HashSet<String> getOrgRoleCode(Long orgId) {
        HashSet<String> roleSet = (HashSet<String>) redisTemplate.opsForHash().get(
                RbacRoleConstants.ORG_ROLE_CODES_KEY, orgId);
        if (ObjectUtils.isNull(roleSet)) {
            roleSet = new HashSet<>();
            List<RbacOrgRoleEntity> list = this.getOrgRoleListByOrgId(orgId);
            if (CollectionUtils.isNotEmpty(list)) {
                for (RbacOrgRoleEntity entity : list) {
                    roleSet.add(entity.getRoleCode());
                }
            }
            // 存储缓存，空列表也缓存
            redisTemplate.opsForHash().put(
                    RbacRoleConstants.ORG_ROLE_CODES_KEY, orgId, roleSet);
        }
        return roleSet;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<RbacOrgRoleEntity> getOrgRoleListByOrgId(Long orgId) {
        List<RbacOrgRoleEntity> roleList =
                (List<RbacOrgRoleEntity>) redisTemplate.opsForHash().get(
                RbacRoleConstants.ORG_ROLE_LIST_KEY, orgId);
        if (CollectionUtils.isEmpty(roleList)) {
            QueryWrapper<RbacOrgRoleEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("org_id", orgId);
            roleList = this.list(queryWrapper);
            this.updateRedisData(orgId, roleList);
        }
        return roleList;
    }

    @Override
    public void updateRedisData(Long orgId, List<RbacOrgRoleEntity> roles) {
        // orgId -> role entity list
        redisTemplate.opsForHash().put(
                RbacRoleConstants.ORG_ROLE_LIST_KEY, orgId, roles);
        HashSet<String> roleCodes = new HashSet<>();
        List<Long> ids = new ArrayList<>();
        for (RbacOrgRoleEntity entity : roles) {
            roleCodes.add(entity.getRoleCode());
            ids.add(entity.getRoleId());
        }
        // orgId -> roleCode list
        redisTemplate.opsForHash().put(
                RbacRoleConstants.ORG_ROLE_CODES_KEY, orgId, roleCodes);
        // orgId -> roleId list
        redisTemplate.opsForHash().put(
                RbacRoleConstants.ORG_ROLE_IDS_KEY, orgId, ids);
    }

    @Override
    public void deleteRedisData(Long orgId) {
        redisTemplate.opsForHash().delete(
                RbacRoleConstants.ORG_ROLE_LIST_KEY, orgId);
        redisTemplate.opsForHash().delete(
                RbacRoleConstants.ORG_ROLE_CODES_KEY, orgId);
        redisTemplate.opsForHash().delete(
                RbacRoleConstants.ORG_ROLE_IDS_KEY, orgId);
    }
}
